<!-- 
    仿淘宝sku的例子；
    参考：vue-sku
    https://github.com/768680109/vue-sku
    电商平台商品 SKU 组合查询算法实现:
    https://hooray.github.io/posts/8b2bd6f8/
-->
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>0713-(vue-sku总结学习)</title>
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
        <style></style>
    </head>
    <body>
        <div id="app">
            <el-row type="flex" class="sku-info">
                <el-col v-for="(attr, index) in process_attribute" :key="index">
                    <h3>{{ attr.name }}</h3>
                    <el-button-group>
                        <el-button
                            v-for="(item, index2) in attr.item"
                            :key="index2"
                            :type="item.actived ? 'primary' : ''"
                            :disabled="item.disabled"
                            @click="skuClick(index, index2)"
                            >{{ item.name }}</el-button
                        >
                    </el-button-group>
                </el-col>
            </el-row>
            <div style="margin-top: 20px">
                库存：
                <span>{{ stock }}</span>
            </div>
            <div style="margin-bottom: 20px">
                价格：
                <span v-if="minprice == maxprice">{{ minprice }}</span>
                <span v-else>{{ minprice }} - {{ maxprice }}</span>
            </div>
            <el-button type="primary" @click="submit">购买</el-button>
            <el-row type="flex" :gutter="20">
                <el-col>
                    <el-divider content-position="left">加工处理过的 attribute 数据</el-divider>
                    <div style="max-height:600px;overflow-y:scroll;">
                    <pre><code>{{ process_attribute }}</code></pre>
                    </div>
                </el-col>
                <el-col>
                    <el-divider content-position="left">加工处理过的 sku 数据</el-divider>
                    <div style="max-height:600px;overflow-y:scroll;">
                    <pre><code>{{ process_sku }}</code></pre>
                    </div>
                </el-col>
            </el-row>
        </div>
    </body>
     <!-- import Vue before Element -->
     <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
    <!-- import JavaScript -->
    <!-- <script src="https://unpkg.com/element-ui/lib/index.js"></script> -->
    <script src="https://unpkg.com/element-ui@2.13.0/lib/index.js"></script>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    // sku字段分隔符
                    separator: ';',
                    attribute: [
                        {
                            name: '颜色',
                            item: ['黑', '金', '白']
                        },
                        {
                            name: '内存',
                            item: ['16G', '32G']
                        },
                        {
                            name: '运营商',
                            item: ['电信', '移动', '联通']
                        }
                    ],
                    sku: [
                        { sku: '黑;16G;电信', price: 100, stock: 0 },
                        { sku: '黑;16G;移动', price: 101, stock: 0 },
                        { sku: '黑;16G;联通', price: 102, stock: 0 },
                        { sku: '黑;32G;电信', price: 103, stock: 0 },
                        { sku: '黑;32G;移动', price: 104, stock: 0 },
                        { sku: '黑;32G;联通', price: 105, stock: 0 },
                        { sku: '金;16G;电信', price: 106, stock: 16 },
                        { sku: '金;16G;移动', price: 107, stock: 17 },
                        { sku: '金;16G;联通', price: 108, stock: 18 },
                        { sku: '金;32G;电信', price: 109, stock: 0 },
                        { sku: '金;32G;移动', price: 110, stock: 20 },
                        { sku: '金;32G;联通', price: 111, stock: 21 },
                        { sku: '白;16G;电信', price: 112, stock: 0 },
                        { sku: '白;16G;移动', price: 113, stock: 23 },
                        { sku: '白;16G;联通', price: 114, stock: 24 },
                        { sku: '白;32G;电信', price: 115, stock: 0 },
                        { sku: '白;32G;移动', price: 116, stock: 26 },
                        { sku: '白;32G;联通', price: 117, stock: 27 }
                    ],
                    process_attribute: [],
                    process_sku: [],
                    // 当前选中 sku 的库存及价格区间
                    stock: '',
                    minprice: '',
                    maxprice: '',

                    selectSku:'白;32G;联通'
                };
            },
            mounted() {
                this.init();
            },
            methods: {
                init() {
                  //新增start
                  let selectSkuList = []
                    if(this.selectSku){
                      selectSkuList=this.selectSku.split(this.separator)
                    }
                  // 新增end

                    // 对 attribute 数据进行加工，并存入 process_attribute 中
                    this.attribute.map((attr,index) => {
                        let temp = {
                            name: attr.name
                        };
                        temp.item = attr.item.map((item) => {
                            return {
                                name: item,
                                // actived: false,
                                actived: item==selectSkuList[index] ? true : false,
                                disabled: false
                            };
                        });
                        this.process_attribute.push(temp);
                    });
                    // 对 sku 数据进行加工，并存入 process_sku 中
                    this.sku.map((v) => {
                        var combArr = this.arrayCombine(v.sku.split(this.separator));
                        //console.log('combArr',combArr)
                        for (var j = 0; j < combArr.length; j++) {
                            var key = combArr[j].join(this.separator);
                            if (this.process_sku[key]) {
                                // 库存累加，价格添加进数组
                                this.process_sku[key].stock += v.stock;
                                this.process_sku[key].prices.push(v.price);
                            } else {
                                this.process_sku[key] = {
                                    stock: v.stock,
                                    prices: [v.price]
                                };
                            }
                        }
                    });
                    // 更新数据视图
                    this.process_sku = Object.assign({}, this.process_sku);
                    this.getPriceStock();
                    //初始化刚开始的数据是否可点击
                    if(selectSkuList.length===0){
                        this.initBtnDisabled()

                    }else {
                      this.setBtnDisabled()
                    }
                   
                },
                arrayCombine(targetArr) {
                    var resultArr = [];
                    for (var n = 0; n <= targetArr.length; n++) {
                        var flagArrs = this.getFlagArrs(targetArr.length, n);
                        while (flagArrs.length) {
                            var flagArr = flagArrs.shift();
                            var combArr = Array(targetArr.length);
                            for (var i = 0; i < targetArr.length; i++) {
                                if (flagArr[i]) {
                                    combArr[i] = targetArr[i];
                                }
                            }
                            resultArr.push(combArr);
                        }
                    }
                    return resultArr;
                },
                getFlagArrs(m, n) {
                    var flagArrs = [],
                        flagArr = [],
                        isEnd = false;
                    for (var ii = 0; ii < m; ii++) {
                        flagArr[ii] = ii < n ? 1 : 0;
                    }
                    flagArrs.push(flagArr.concat());
                    // 当n不等于0并且m大于n的时候进入
                    if (n && m > n) {
                        while (!isEnd) {
                            var leftCnt = 0;
                            for (var i = 0; i < m - 1; i++) {
                                if (flagArr[i] == 1 && flagArr[i + 1] == 0) {
                                    for (var j = 0; j < i; j++) {
                                        flagArr[j] = j < leftCnt ? 1 : 0;
                                    }
                                    flagArr[i] = 0;
                                    flagArr[i + 1] = 1;
                                    var aTmp = flagArr.concat();
                                    flagArrs.push(aTmp);
                                    if (aTmp.slice(-n).join('').indexOf('0') == -1) {
                                        isEnd = true;
                                    }
                                    break;
                                }
                                flagArr[i] == 1 && leftCnt++;
                            }
                        }
                    }
                    return flagArrs;
                },
                skuClick(key1, key2) {
                    if (!this.process_attribute[key1].item[key2].disabled) {
                        this.process_attribute[key1].item.map((item, index) => {
                            item.actived = index == key2 ? !item.actived : false;
                        });
                        //价格，库存
                        this.getPriceStock();
                        // 设置按钮能否点击disabled
                        // this.getStockPrice(key1, key2);//修改函数名字
                        this.changeBtnDisabled(key1, key2)
                    }
                },
                //获取价格或库存
                // skuCheck() {
                getPriceStock() {
                    let sku = [];
                    this.process_attribute.map((attr) => {
                        let name = '';
                        attr.item.map((item) => {
                            if (item.actived) {
                                name = item.name;
                            }
                        });
                        sku.push(name);
                    });
                    console.log('getPriceStock----sku',sku)
                    this.stock = this.process_sku[sku.join(this.separator)].stock;
                    this.minprice = Math.min.apply(
                        Math,
                        this.process_sku[sku.join(this.separator)].prices
                    );
                    this.maxprice = Math.max.apply(
                        Math,
                        this.process_sku[sku.join(this.separator)].prices
                    );
                },
                //设置按钮的disaled状态
                // getStockPrice(key1, key2) {
                changeBtnDisabled(key1, key2) {
                  //console.log('this.process_attribute[key1].item[key2]',this.process_attribute[key1].item[key2].name)
                  this.process_attribute.map((attr) => {
                      attr.item.map((item) => {
                          item.disabled = false;
                      });
                  });
                  let haveChangedAttribute = Array(this.process_attribute.length)
                  let isEmpty = true //判断是否有选中
                  this.process_attribute.map((item1,index1)=>{
                    item1.item.map((item2,index2)=>{
                      if(item2.actived===true){
                        haveChangedAttribute[index1]=item2.name
                        isEmpty = false
                      }
                    })
                  })
                  //console.log('haveChangedAttribute',haveChangedAttribute)
                  if(!isEmpty){
                    //用已经选中的节点验证待测试节点
                    let daiceshis = [] //存储待测试的所有节点
                    let daiceshiNames = [] //存储待测试的所有name值，1.1主要用于从待测试的节点中删除已经选中过的，
                    this.process_attribute.map((item1,index1)=>{
                      item1.item.map((item2,index2)=>{
                        if(this.process_attribute[key1].item[key2].name!=item2.name){
                          daiceshis.push({
                            index:index1,
                            cindex:index2,
                            name:item2.name
                          })
                          daiceshiNames.push(item2.name)
                        }
                      })
                    })
                    //console.log('daiceshis11',daiceshis)
                    //console.log('daiceshiNames11',daiceshiNames)
                    //同上1.1删除操作判断
                    haveChangedAttribute.forEach((item,index)=>{
                      let indexs = daiceshiNames.indexOf(item)
                      if(indexs > -1){
                        daiceshis.splice(indexs,1)
                        daiceshiNames.splice(indexs,1)
                      }
                    })

                    //console.log('daiceshis22',daiceshis)
                    //console.log('daiceshiNames22',daiceshiNames)
                    //组合待测试的节点
                    daiceshis.forEach((item)=>{
                      let testAttrNames = Array(this.process_attribute.length) ; // 保存激活节点和待测试的组合
                      let siblingsName = '' // 保存当前的属性是否有选中的节点
                      this.process_attribute[item.index].item.forEach(citem=>{
                        if(citem.actived===true){
                          siblingsName = citem.name
                        }
                      })
                      //console.log('siblingsName',siblingsName)
                      if(siblingsName!=''){
                        haveChangedAttribute.forEach((hItem,hIndex)=>{
                          (hItem !=siblingsName) && (testAttrNames[hIndex] = hItem)
                        })
                        //console.log('testAttrNames11',testAttrNames)
                      } else {
                        testAttrNames = haveChangedAttribute.concat()
                        //console.log('testAttrNames22',testAttrNames)
                      }
                      //console.log(testAttrNames)

                      // 待测试节点数据补充
                      testAttrNames[item.index] = item.name
                      //console.log('testAttrNames33',testAttrNames)

                      let attrString = testAttrNames.join(this.separator)
                      if(this.process_sku[attrString]&&this.process_sku[attrString].stock){
                        this.process_attribute[item.index].item[item.cindex].disabled = false
                      }else {
                        this.process_attribute[item.index].item[item.cindex].disabled = true
                      }
                    })
                    

                  }else{
                    // 没有选中的状态时
                    console.log('没有选中的状态')
                    this.initBtnDisabled()
                  }
                },
                //一个sku都没有选时按钮的disabled
                initBtnDisabled(){
                  this.process_attribute.forEach((item1,index1)=>{
                      item1.item.forEach((item2,index2)=>{
                        let testAttrs = Array(this.process_attribute.length)
                        testAttrs[index1] = item2.name
                        let testAttrsStr = testAttrs.join(this.separator)
                        if(this.process_sku[testAttrsStr] && this.process_sku[testAttrsStr].stock){
                          item2.disabled = false
                        }else {
                          item2.disabled = true
                        }
                      })
                  })
                },
                setBtnDisabled(){
                  console.log('初始化有选中sku')
                  let haveChangedAttribute = this.selectSku.split(this.separator)
                  console.log(haveChangedAttribute)
                  //用已经选中的节点验证待测试节点
                   let daiceshis = [] //存储待测试的所有节点
                    let daiceshiNames = [] //存储待测试的所有name值，1.1主要用于从待测试的节点中删除已经选中过的，
                    this.process_attribute.map((item1,index1)=>{
                      item1.item.map((item2,index2)=>{
                        // if(this.process_attribute[key1].item[key2].name!=item2.name){
                          daiceshis.push({
                            index:index1,
                            cindex:index2,
                            name:item2.name
                          })
                          daiceshiNames.push(item2.name)
                        // }
                      })
                    })
                    //console.log('daiceshis11',daiceshis)
                    //console.log('daiceshiNames11',daiceshiNames)
                    //同上1.1删除操作判断
                    haveChangedAttribute.forEach((item,index)=>{
                      let indexs = daiceshiNames.indexOf(item)
                      if(indexs > -1){
                        daiceshis.splice(indexs,1)
                        daiceshiNames.splice(indexs,1)
                      }
                    })

                    //console.log('daiceshis22',daiceshis)
                    //console.log('daiceshiNames22',daiceshiNames)
                    //组合待测试的节点
                    daiceshis.forEach((item)=>{
                      let testAttrNames = Array(this.process_attribute.length) ; // 保存激活节点和待测试的组合
                      let siblingsName = '' // 保存当前的属性是否有选中的节点
                      this.process_attribute[item.index].item.forEach(citem=>{
                        if(citem.actived===true){
                          siblingsName = citem.name
                        }
                      })
                      //console.log('siblingsName',siblingsName)
                      if(siblingsName!=''){
                        haveChangedAttribute.forEach((hItem,hIndex)=>{
                          (hItem !=siblingsName) && (testAttrNames[hIndex] = hItem)
                        })
                        //console.log('testAttrNames11',testAttrNames)
                      } else {
                        testAttrNames = haveChangedAttribute.concat()
                        //console.log('testAttrNames22',testAttrNames)
                      }
                      //console.log(testAttrNames)

                      // 待测试节点数据补充
                      testAttrNames[item.index] = item.name
                      //console.log('testAttrNames33',testAttrNames)

                      let attrString = testAttrNames.join(this.separator)
                      if(this.process_sku[attrString]&&this.process_sku[attrString].stock){
                        this.process_attribute[item.index].item[item.cindex].disabled = false
                      }else {
                        this.process_attribute[item.index].item[item.cindex].disabled = true
                      }
                    })
                },

                submit() {
                    let sku = [];
                    let isSelectSKU = this.process_attribute.every((attr) => {
                        let filter = attr.item.filter((v) => v.actived);
                        if (filter.length != 0) {
                            sku.push(filter[0].name);
                        }
                        return filter.length != 0;
                    });
                    if (isSelectSKU) {
                        this.$message.success(`当前SKU为：${sku.join(this.separator)}`);
                    } else {
                        this.$message.warning('请选择完整商品属性');
                    }
                }
            }
        });
    </script>
</html>
